package com.lbz.controller.front;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.demo.trade.config.Configs;
import com.google.common.collect.Maps;
import com.lbz.common.Constant;
import com.lbz.common.ServerResponse;
import com.lbz.dao.OrderMapper;
import com.lbz.dao.PayInfoMapper;
import com.lbz.service.PayInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author 林必昭
 * @Date 2019/6/28 22:56
 *
 * <p>
 * 返回结果:
 * success
 * success
 * fail
 * failed
 * </p>
 */

@RequestMapping("/payInfo/")
public class AlipayCallbackController {

    private static final Logger logger = LoggerFactory.getLogger(AlipayCallbackController.class);

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private PayInfoService payInfoService;

    @Autowired
    private PayInfoMapper payInfoMapper;

    @RequestMapping("alipay_callback.do")
    @ResponseBody
    public Object alipayCallback(HttpServletRequest request) {
        Map<String, String> params = Maps.newHashMap();

        //从request里获取到回调的参数
        Map requestParamsMap = request.getParameterMap();
        //遍历回调参数
        for (Iterator iterator = requestParamsMap.keySet().iterator(); iterator.hasNext(); ) {
            //requestParamsMap.keySet().iterator()获取所有的key值
            String name = (String) iterator.next();
            String[] values = (String[]) requestParamsMap.get(name);    //获取value数组集合
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";    //value1,value2,value3,value4,...,value[length-1]
            }
            params.put(name, valueStr);  //将异步通知中收到的待验证所有参数都存放到map中
        }
        logger.info("支付宝回调,签名-sign:{},交易状态-trade_status:{},参数:{}", params.get("sign"), params.get("trade_status"), params.toString());

        /**
         * <p>
         *     (验签)验证回调的正确性，是不是支付宝发的，并且要避免重复通知，支付宝验签的
         *     方法在AlipaySignature类中，支付宝已经帮我们封装好了，需要注意的是，我们使用
         *     的验签方法是 public static boolean rsaCheckV2(Map<String, String> params,
         *     String publicKey,String charset,String signType)该方法
         * </p>
         *
         * 第一步: 在通知返回的参数列表中，出去sign、sign_type两个参数意外，凡是通知返回回来的参数都要经过验签。
         * 第二步：将剩下参数进行 url_decode, 然后进行字典排序，组成字符串，得到待签名字符串
         * 第三步：将签名参数（sign）使用 base64 解码为字节码串。
         * 第四步：使用RSA的验签方法，通过签名字符串、签名参数（经过 base64 解码）及支付宝公钥验证签名。
         * 第五步：在步骤四验证签名正确后，必须再严格按照如下描述校验通知数据的正确性。
         *
         *      1.商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
         *      2.判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）
         *      3.校验通知中的 seller_id（或者 seller_email ) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
         *      4.验证 app_id 是否为该商户本身。上述 1、2、3、4有任何一个验证不通过，则表明本次通知是异常通知，务必忽略,在上述验证通过后商户必须根据支付宝不同类型
         *        的业务通知，正确的进行不同的业务处理，并且过滤重复的通知结果数据。在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，
         *        支付宝才会认定为买家付款成功。
         */

//        params.remove("sign");  //签名,支付宝已经帮我们去掉了
        params.remove("sign_type");   //签名类型，商户生成签名字符串锁使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2
        try {
            //注意这里调用的是：rsaCheckV2(Map<String, String> params, String publicKey,String charset,String signType) publicKey是支付宝公钥，不是商家公钥
            boolean alipayRSACheckedV2Result = AlipaySignature.rsaCheckV2(params, Configs.getAlipayPublicKey(), "utf-8", Configs.getSignType());
            if (!alipayRSACheckedV2Result) {
                return ServerResponse.createByErrorMessage("非法请求，验证不通过，再次而已请求会自动报警");
            }
        } catch (AlipayApiException e) {
            logger.error("支付宝验证回调异常", e);
            e.printStackTrace();
        }
        // todo 验证各种数据
        // todo 业务逻辑，验证成功之后，要对商品库存更新
        ServerResponse serverResponse = payInfoService.alipayCallback(params);
        if (serverResponse.isSuccess()) {
            return Constant.AlipayCallback.RESPONSE_SUCCESS;
        }
        return Constant.AlipayCallback.RESPONSE_FAILED;
    }


}
